/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
 /*
 * Topology Viewer
 */


package cgl.narada.topology.viewer;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.File;
import java.io.FileInputStream;

import javax.imageio.ImageIO;
import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.ServiceUI;
import javax.print.SimpleDoc;
import javax.print.attribute.DocAttributeSet;
import javax.print.attribute.HashDocAttributeSet;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.swing.JFileChooser;
import javax.swing.JPanel;


//import com.ibm.ibmts.*;

/**
 * Represets the visual screen over which all the pictures are drawn.
 */
public class Screen extends JPanel implements MouseListener,
					      MouseMotionListener {
    private static int NODE_INFO = 1;
    private static int LINK_INFO = 2;
    public NodeManagement nodeManagement;
    public int screenCenterX, screenCenterY;
    public int mode;

    private boolean inSave, inPrint, firstTime;
    private int shotCount;
    private Image I;
    private LowerScreen lowerScreenPanel;
    private Dimension panelDimension;
    private int numNodesSelected;
    private ImageObserver observer;
    private Node endNode1, endNode2;
    private Color originalColor1, originalColor2;

    public int numNodes;

    /**
     * Only constructor doing initializations of color, size, variables.
     */
    public Screen(NodeManagement nm) {
	// display related things
	lowerScreenPanel = new LowerScreen();
	firstTime = true;
	inSave = false;
	inPrint = false;
	numNodesSelected = 0;
	shotCount = 1;
	mode = 1;
	this.addMouseListener(this);
	this.addMouseMotionListener(this);
	panelDimension = new Dimension(800, 560);
	setPreferredSize(panelDimension);
        setBackground(Color.white);
        setDoubleBuffered(true);

	nodeManagement = nm;
	setInitialPositions();
    }

    /**
     * Returns <code>LowerScreen</code> panel.
     */
    public LowerScreen getLowerScreenPanel() {
	return lowerScreenPanel;
    }

    /**
     * Sets initial positions for all the components in 
     * <code>NodeManagement</code>
     */
    public void setInitialPositions() {
	firstTime = true;
	panelDimension = getSize();
	int limX2 = getX() + panelDimension.width;
	int limY2 = getY() + panelDimension.height;
	screenCenterX = getX() + (panelDimension.width  / 2);
	screenCenterY = getY() + (panelDimension.height / 2);
	nodeManagement.setInitialPositions(screenCenterX,
					   screenCenterY,
					   getX(), 
					   getY(), 
					   getX() + panelDimension.width,
					   getY() + panelDimension.height);
    }
    
    /**
     * Calls paintComponent() for this screen.
     */
    public void display() {
	if (firstTime) {
	    setInitialPositions();
	}
	// change the Image if the panel dimensions are changed.
	if ((panelDimension.width != getSize().width)
	    &&(panelDimension.height != getSize().height)) {
	    panelDimension = getSize();
	    panelDimension.width = (panelDimension.width == 0) ? 1 
		: panelDimension.width;
	    panelDimension.height = (panelDimension.height == 0) ? 1 
		: panelDimension.height;
	    I = createImage(panelDimension.width, panelDimension.height);
	}
	firstTime = false;
	paintComponent(getGraphics());
    }

    /**
     * Overriding method. Repaints whole screen containing topology
     * view.
     */
    public void paintComponent(Graphics g) {
	if (firstTime) {
	    panelDimension = getSize();
	    panelDimension.width = (panelDimension.width == 0) ? 1 
		: panelDimension.width;
	    panelDimension.height = (panelDimension.height == 0) ? 1 
		: panelDimension.height;
	    I = createImage(panelDimension.width, 
			    panelDimension.height);
	}
	// if the image is being saved or printed then make use of other image
	// so that Image I is reserved for saving or printing.
	if ((!inSave) && (!inPrint)) {
	    Graphics gi = I.getGraphics();
	    nodeManagement.setGraphics(gi);
	    gi.setColor(Color.WHITE);
	    gi.fillRect(0, 0, panelDimension.width, panelDimension.height);
	    nodeManagement.drawView();
	    g.drawImage(I, getX(), getY(), panelDimension.width, 
			panelDimension.height, Color.white, observer);
	} else {
	    Image I1 = createImage(panelDimension.width, 
				   panelDimension.height);
	    Graphics gi1 = I1.getGraphics();
	    nodeManagement.setGraphics(gi1);
	    nodeManagement.drawView();
	    g.drawImage(I1, getX(), getY(), panelDimension.width, 
			panelDimension.height, Color.white, observer);
	}
	lowerScreenPanel.setCountString(nodeManagement.getCountInformation());
	lowerScreenPanel.display();
    }

    /**
     * Saves the current picture into the file at location choosed by the 
     * user.
     * @throws TopologyException in case error during image saving.
     */
    public void saveScreen() throws TopologyException {
	inSave = true;
	JFileChooser fc = new JFileChooser();
	ImageFilter imageFilter = new ImageFilter();
	fc.addChoosableFileFilter(imageFilter);
	int returnValue = fc.showSaveDialog(this);
	if (returnValue == JFileChooser.APPROVE_OPTION) {
	    File imageFile = fc.getSelectedFile();
	    if (Utils.getExtension(imageFile) == null) {
		imageFile = new File(imageFile.toString() + ".png");
	    } else if (!(Utils.getExtension(imageFile)).equals(Utils.png)) {
		imageFile = new File(imageFile.toString() + ".png");
	    }
	    try {
		if (ImageIO.write((BufferedImage)I, "png", imageFile)) {
		    shotCount++;
		}
		else {
		    throw new TopologyException("Error saving the file");
		}
	    } catch(Exception e) {
		throw new TopologyException("Error during image write");
	    }
	}
	inSave = false;
    }

    /**
     * Prints the current picture.
     * @throws TopologyException in case of any error during image printing.
     */
    public void printScreen() throws TopologyException {
	inPrint = true;
	File imageFile = new File(".\\printShot.png");
	try {
	    if (ImageIO.write((BufferedImage)I, "png", imageFile)) {
	    }
	    else {
		throw new TopologyException("Error writing the file");
	    }
	    PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
	    DocFlavor flavor = DocFlavor.INPUT_STREAM.PNG;
	    PrintService printService[] = 
		PrintServiceLookup.lookupPrintServices(flavor, pras);
	    PrintService defaultService = 
		PrintServiceLookup.lookupDefaultPrintService();
	    PrintService service = ServiceUI.printDialog(null, 200, 200,
							 printService,
							 defaultService, flavor,
							 pras);
	    if (service != null) {
		DocPrintJob job = service.createPrintJob();
		FileInputStream fis = new FileInputStream(imageFile);
		DocAttributeSet das = new HashDocAttributeSet();
		Doc doc = new SimpleDoc(fis, flavor, das);
		job.print(doc, pras);
		//Thread.sleep(10000);
	    }
	} catch(Exception e) {
	    throw new TopologyException("Error during image print");
	}
	inPrint = false;
    }

    /**
     * Overriding method of <code>MouseListener</code>. Handles left and
     * right click events.
     * @param me <code>MouseEvent</code>
     */ 
    public void mouseClicked(MouseEvent me) {
	int modifier = me.getModifiers();
	if (modifier == InputEvent.BUTTON3_MASK) { 
	    // right click

	    // Following Section to be used for measuring response delay to
	    // fetch node information
	    // ibmtslink ibmt = new ibmtslink();
	    // long epoch1 = ibmt.getEpochMicroseconds();
	    Node nodeToDisplay = 
		    nodeManagement.getNodeAtParticularCoordinates(me.getX(),
								  me.getY());
	    // long epoch2 = ibmt.getEpochMicroseconds();
	    // System.out.println(numNodes + " " + (epoch2 - epoch1));
	    if (nodeToDisplay != null) {
		if (mode == NODE_INFO) {
		    // show node information on right click
		    if (endNode1 != null) {
			endNode1.nodeLocation.setColor(originalColor1);
		    } 
		    if (endNode2 != null) {
			endNode2.nodeLocation.setColor(originalColor2);
		    }
		    NodeFrame nf = 
			new NodeFrame(nodeToDisplay,
				      nodeManagement.linkManagement.getAllLinksForNode(nodeToDisplay), nodeManagement.getAllClientsForNode(nodeToDisplay));
		    //nf.display();
		} else if (mode == LINK_INFO) {
		    // show link information on right click
		    if (numNodesSelected == 0) {
			if (endNode1 != null) {
			    endNode1.nodeLocation.setColor(originalColor1);
			} 
			if (endNode2 != null) {
			    endNode2.nodeLocation.setColor(originalColor2);
			}
		    }
		    numNodesSelected++;
		    if (numNodesSelected == 1) {
			// one end of link selected
			endNode1 = nodeToDisplay;
			originalColor1 = endNode1.nodeLocation.getColor();
			endNode1.nodeLocation.setColor(Color.BLACK);
		    } else if (numNodesSelected == 2) {
			endNode2 = nodeToDisplay;
			originalColor2 = endNode2.nodeLocation.getColor();
			endNode2.nodeLocation.setColor(Color.BLACK);
			NodeFrame nf = 
			    new NodeFrame(endNode1, endNode2, 
					  nodeManagement.linkManagement.getAllLinksForPair(endNode1, endNode2));
		    }
		    //nf.display();
		    if (numNodesSelected == 2) {
			numNodesSelected = 0;
		    }
		}
	    }
	} else {
	    // left click
	    if (numNodesSelected == 0) {
		if (endNode1 != null) {
		    endNode1.nodeLocation.setColor(originalColor1);
		} 
		if (endNode2 != null) {
		    endNode2.nodeLocation.setColor(originalColor2);
		}
	    }
	    panelDimension = getSize();
	    nodeManagement.recenter(me.getX(), me.getY(),
				    (getX() + panelDimension.width) / 2,
				    (getY() + panelDimension.height) / 2);
	    display();
	}
    }

    public void mouseDragged(MouseEvent me) {}
    public void mousePressed(MouseEvent me) {}
    public void mouseReleased(MouseEvent me) {}
    public void mouseExited(MouseEvent me) {}
    public void mouseEntered(MouseEvent me) {} 
    public void mouseMoved(MouseEvent me) {}
};
    
